/*
 * ========================================
 * RISC-V 最小操作系统主函数
 * ========================================
 * 
 * 这个文件包含操作系统的主函数，是整个C语言部分的入口点。
 * 从汇编代码entry.S调用main函数后，程序的控制权就转移到这里。
 * 
 * 主要功能：
 * 1. 初始化UART串口
 * 2. 测试printf和清屏功能
 * 3. 进入无限循环防止程序退出
 */

// 包含必要的头文件
#include "../include/types.h"
#include "../include/printf.h"
#include "../include/memory.h"

// ========================================
// 函数声明（前向声明）
// ========================================
//
// 在C语言中，如果函数定义在使用之后，需要先声明函数原型
// 这样编译器就知道这些函数的存在和参数类型

// UART初始化函数：设置串口的基本参数
void uart_init(void);

// 内存管理测试函数
void test_memory_management(void);

// ========================================
// 测试函数
// ========================================

// 测试基本printf功能
void test_printf_basic(void)
{
    printf("=== 基本printf功能测试 ===\n");
    
    // 测试整数
    printf("整数测试: %d\n", 42);
    printf("负数测试: %d\n", -123);
    printf("零值测试: %d\n", 0);
    
    // 测试十六进制
    printf("十六进制测试: 0x%x\n", 0xABC);
    printf("大写十六进制: 0x%X\n", 0xDEF);
    
    // 测试字符串
    printf("字符串测试: %s\n", "Hello OS");
    printf("空字符串测试: '%s'\n", "");
    
    // 测试字符
    printf("字符测试: %c\n", 'X');
    
    // 测试百分号
    printf("百分号测试: %%\n");
    
    printf("\n");
}

// 测试边界情况
void test_printf_edge_cases(void)
{
    printf("=== 边界情况测试 ===\n");
    
    // 测试最大最小值
    printf("INT_MAX: %d\n", 2147483647);
    printf("INT_MIN: %d\n", -2147483648);
    
    // 测试NULL指针
    printf("NULL字符串: %s\n", (char*)0);
    
    // 测试指针
    int x = 42;
    printf("指针地址: %p\n", &x);
    
    printf("\n");
}

// 测试清屏功能
void test_clear_screen(void)
{
    printf("=== 清屏功能测试 ===\n");
    printf("\n");
    
    // 输出大量内容填满屏幕
    printf("第1行: 这是测试内容，用来填满屏幕\n");
    printf("第2行: 这是测试内容，用来填满屏幕\n");
    printf("第3行: 这是测试内容，用来填满屏幕\n");
    printf("第4行: 这是测试内容，用来填满屏幕\n");
    printf("第5行: 这是测试内容，用来填满屏幕\n");
    printf("第6行: 这是测试内容，用来填满屏幕\n");
    printf("第7行: 这是测试内容，用来填满屏幕\n");
    printf("第8行: 这是测试内容，用来填满屏幕\n");
    printf("第9行: 这是测试内容，用来填满屏幕\n");
    printf("第10行: 这是测试内容，用来填满屏幕\n");
    printf("第11行: 这是测试内容，用来填满屏幕\n");
    printf("第12行: 这是测试内容，用来填满屏幕\n");
    printf("第13行: 这是测试内容，用来填满屏幕\n");
    printf("第14行: 这是测试内容，用来填满屏幕\n");
    printf("第15行: 这是测试内容，用来填满屏幕\n");
    printf("第16行: 这是测试内容，用来填满屏幕\n");
    printf("第17行: 这是测试内容，用来填满屏幕\n");
    printf("第18行: 这是测试内容，用来填满屏幕\n");
    printf("第19行: 这是测试内容，用来填满屏幕\n");
    printf("第20行: 这是测试内容，用来填满屏幕\n");
    printf("\n");
    printf(">>> 屏幕已填满，马上开始清屏 <<<\n");
    
    // 延时3秒，让用户看清楚屏幕内容
    for (volatile int i = 0; i < 15000000; i++);
    
    // 执行清屏
    clear_screen();
    
    // 清屏后输出确认信息
    printf("=== 清屏完成！ ===\n");
    printf("如果你看到这条消息，说明清屏功能正常工作！\n");
    printf("屏幕上的所有内容都已被清除。\n");
    printf("\n");
}

// 测试颜色输出
void test_color_output(void)
{
    printf("=== 颜色输出测试 ===\n");
    
    printf_color(COLOR_RED, "这是红色文本\n");
    printf_color(COLOR_GREEN, "这是绿色文本\n");
    printf_color(COLOR_YELLOW, "这是黄色文本\n");
    printf_color(COLOR_BLUE, "这是蓝色文本\n");
    printf_color(COLOR_MAGENTA, "这是洋红色文本\n");
    printf_color(COLOR_CYAN, "这是青色文本\n");
    printf_color(COLOR_WHITE, "这是白色文本\n");
    
    printf("\n");
}

// 测试光标控制
void test_cursor_control(void)
{
    printf("=== 光标控制测试 ===\n");
    
    // 输出一些文本
    printf("第1行: 这是第一行文本\n");
    printf("第2行: 这是第二行文本\n");
    printf("第3行: 这是第三行文本\n");
    
    // 等待一下
    for (volatile int i = 0; i < 5000000; i++);
    
    // 光标回到第1行并覆盖
    goto_xy(1, 1);
    printf_color(COLOR_RED, "第1行: 这行已被覆盖！");
    
    // 光标到第2行并清除
    goto_xy(1, 2);
    clear_line();
    printf_color(COLOR_GREEN, "第2行: 这行已被清除并重写");
    
    printf("\n\n");
}

// 测试sprintf功能
void test_sprintf(void)
{
    printf("=== sprintf功能测试 ===\n");
    
    char buf[128];
    
    // 测试基本sprintf
    sprintf(buf, "数字: %d, 字符串: %s", 123, "Hello");
    printf("sprintf结果: %s\n", buf);
    
    // 测试复杂格式化
    sprintf(buf, "十六进制: 0x%x, 字符: %c", 0xFF, 'A');
    printf("复杂格式化: %s\n", buf);
    
    printf("\n");
}

// ========================================
// 主函数：操作系统C语言部分的入口点
// ========================================
//
// 这个函数从汇编代码entry.S中的"call main"指令被调用
// 此时栈已经设置好，BSS段已经清零，可以安全使用C语言特性
//
// 返回值：
// - int：函数返回类型，虽然我们永远不会返回
// - void：无参数
int main(void)
{
    // ========================================
    // 第一步：初始化UART串口
    // ========================================
    //
    // UART (Universal Asynchronous Receiver/Transmitter) 是串口通信设备
    // 在QEMU模拟器中，UART连接到虚拟终端，我们可以通过它输出文本
    // 
    // 为什么需要初始化？
    // - 设置波特率、数据位、停止位等参数
    // - 确保UART处于正确的工作状态
    // - 对于我们的最小实现，使用默认设置即可
    //
    uart_init();
    
    // ========================================
    // 第二步：输出欢迎消息
    // ========================================
    //
    // 这是我们操作系统的第一个输出！
    // "Hello OS\n" 中的 \n 是换行符，让输出更美观
    //
    printf_color(COLOR_GREEN, "=== RISC-V 最小操作系统启动成功 ===\n");
    printf("版本: 1.0.0\n");
    printf("功能: printf, 清屏, 颜色输出, 光标控制\n");
    printf("\n");
    
    // ========================================
    // 第三步：运行功能测试
    // ========================================
    //
    // 测试我们实现的各种功能
    //
    test_printf_basic();
    test_printf_edge_cases();
    test_sprintf();
    
    // 等待用户观察结果
    printf("按任意键继续测试清屏功能...\n");
    for (volatile int i = 0; i < 10000000; i++);
    
    test_clear_screen();
    test_color_output();
    
    // 等待用户观察结果
    printf("按任意键继续测试光标控制...\n");
    for (volatile int i = 0; i < 10000000; i++);
    
    test_cursor_control();
    
    // 等待用户观察结果
    printf("按任意键继续测试内存管理...\n");
    for (volatile int i = 0; i < 10000000; i++);
    
    test_memory_management();
    
    // ========================================
    // 第四步：显示完成信息
    // ========================================
    //
    printf_color(COLOR_CYAN, "=== 所有测试完成 ===\n");
    printf("printf功能正常工作！\n");
    printf("清屏功能正常工作！\n");
    printf("颜色输出正常工作！\n");
    printf("光标控制正常工作！\n");
    printf("\n");
    
    // ========================================
    // 第五步：进入无限循环
    // ========================================
    //
    // 为什么需要无限循环？
    // - 防止main函数返回，导致程序意外退出
    // - 操作系统应该持续运行，不应该"结束"
    // - 如果程序退出，QEMU可能会重启系统
    //
    // 在真实操作系统中，这里通常会调用调度器来运行用户程序
    // 但在我们的最小实现中，只需要保持系统运行即可
    //
    printf_color(COLOR_YELLOW, "系统进入空闲状态，按Ctrl+C退出QEMU\n");
    while(1) {
        // 这里可以添加更多功能，比如：
        // - 处理中断
        // - 运行用户程序
        // - 系统监控
        // 目前我们保持简单，什么都不做
    }
    
    // ========================================
    // 这行代码永远不会被执行
    // ========================================
    //
    // 因为上面的while(1)是无限循环，所以return 0永远不会被执行
    // 但为了代码的完整性和编译器的要求，我们仍然保留这个return语句
    //
    return 0;
}

// ========================================
// 内存管理测试函数
// ========================================

/*
 * 测试内存管理功能
 * 包括物理内存分配和虚拟内存管理
 */
void test_memory_management(void)
{
    printf("=== 内存管理功能测试 ===\n");
    printf("\n");
    
    // 1. 初始化物理内存分配器
    printf("1. 初始化物理内存分配器\n");
    printf("-------------------\n");
    kalloc_init();
    
    // 2. 测试物理内存分配器
    printf("2. 测试物理内存分配器\n");
    printf("-------------------\n");
    
    // 分配几个页面
    void *page1 = kalloc();
    void *page2 = kalloc();
    void *page3 = kalloc();
    
    if (page1 && page2 && page3) {
        printf("✓ 成功分配3个页面\n");
        printf("  页面1地址: 0x%p\n", page1);
        printf("  页面2地址: 0x%p\n", page2);
        printf("  页面3地址: 0x%p\n", page3);
    } else {
        printf("✗ 页面分配失败\n");
    }
    
    // 打印内存统计
    kalloc_print_stats();
    
    // 释放一个页面
    printf("释放页面1...\n");
    kfree(page1);
    kalloc_print_stats();
    
    // 3. 测试虚拟内存管理
    printf("3. 测试虚拟内存管理\n");
    printf("-------------------\n");
    
    // 初始化虚拟内存系统
    vm_init();
    
    // 启用虚拟内存
    vm_enable();
    
    // 打印虚拟内存统计
    vm_print_stats();
    
    // 测试页表功能
    vm_test();
    
    printf("内存管理测试完成！\n");
    printf("==================\n\n");
}
